#include "QueryPlanner.h"

using namespace std;

// Initialize static map
map<int, Pipe*> OperatorNode::Pipes;


void SelectPipeNode::PrintNode()
{
	if (this->left != NULL)
		this->left->PrintNode();

	cout << "\n  Select Pipe Operator ";
	cout << "\n Input pipe ID: " << InPipe;
	cout << "\n Output pipe ID: " << OutPipe;
	cout << "\n CNF : ";
	if (cnf != NULL)
		cnf->Print();
	else
		cout << "NULL";


	if (this->right != NULL)
		this->right->PrintNode();
}
//post order traversal
void SelectPipeNode::ExecutePostOrder()
{
	if (this->left)
		this->left->ExecutePostOrder();
	if (this->right)
		this->right->ExecutePostOrder();
	this->ExecuteNode();
}

void SelectPipeNode::ExecuteNode()
{

	//from Relop.h
	SelectPipe selPipe;
	selPipe.Use_n_Pages(USE_PAGES);
	if (cnf != NULL && literal != NULL)
	{
		selPipe.Run(*(OperatorNode::Pipes[InPipe]), *(OperatorNode::Pipes[OutPipe]), *cnf, *literal);
	}
	else
		cout << "\n check parameters!\n";
}



void SelectFileNode::PrintNode()
{
	if (this->left != NULL)
		this->left->PrintNode();

	if (this->right != NULL)
		this->right->PrintNode();

	cout << "\nSelect File ";
	cout << "\nOutput pipe ID: " << OutPipe;
	cout << "\nInput filename: " << InFileName.c_str();
	cout << "\nCNF : ";
	if (cnf != NULL)
		cnf->Print();
	else
		cout << "NULL";

}

void SelectFileNode::ExecutePostOrder()
{
	if (this->left)
		this->left->ExecutePostOrder();
	if (this->right)
		this->right->ExecutePostOrder();
	this->ExecuteNode();
}

void SelectFileNode::ExecuteNode()
{
	//instance of db file using the inpfile name and its path
	DBFile * dbFile = new DBFile;
	dbFile ->Open(const_cast<char*>(InFileName.c_str())); 

	SelectFile *selectfile = new SelectFile();
	selectfile->Use_n_Pages(USE_PAGES);
	if (cnf != NULL && literal != NULL)
	{
		selectfile->Run(*dbFile , *(OperatorNode::Pipes[OutPipe]), *cnf, *literal);
	}
	else
		cout << "\n check parameters!\n";
}



void ProjectNode::PrintNode()
{
	if (this->left != NULL)
		this->left->PrintNode();

	cout << "\n  Project Node ";
	cout << "\n Input pipe ID: " << InPipe;
	cout << "\n Output pipe ID: " << OutPipe;
	cout << "\nNum atts to Keep: " << attsToKeep;
	cout << "\nNum total atts: " << totAtts;
	if (atts!= NULL)
	{
		cout << "\nAttributes to keep: ";
		for (int i = 0; i < attsToKeep; i++)
			cout << atts[i] << " ";
	}

	if (this->right != NULL)
		this->right->PrintNode();
}

void ProjectNode::ExecutePostOrder()
{
	if (this->left)
		this->left->ExecutePostOrder();
	if (this->right)
		this->right->ExecutePostOrder();
	this->ExecuteNode();
}

void ProjectNode::ExecuteNode()
{ 
	Project *project = new Project();
	project->Use_n_Pages(USE_PAGES);
	if (atts != NULL)
	{
		cout << "Staring Project with Input " << InPipe << " Out: " << OutPipe << "\n";
		project->Run(*(OperatorNode::Pipes[InPipe]), *(OperatorNode::Pipes[OutPipe]),
				atts, totAtts,attsToKeep);
		cout << "Started project\n";
		if (print== 1)
		{
			Record rec;
			int count = 0;
			while (OperatorNode::Pipes[OutPipe]->Remove(&rec))
			{
				rec.Print(sch);
				count++;
			}
			cout << endl << count << " records removed from pipe " << OutPipe << endl;
		}
	}
	else
		cout << "\n check parameters!\n";
}


void JoinNode::PrintNode()
{
	if (this->left != NULL)
		this->left->PrintNode();

	if (this->right != NULL)
		this->right->PrintNode();

	cout << "\n  Join ";
	cout << "\nInput pipe-Left ID: " << InPipe;
	cout << "\nInput pipe-Right ID: " << rightInPipe;
	cout << "\nOutput pipe ID: " << OutPipe;
	cout << "\n CNF : ";
	if (cnf!= NULL)
		cnf->Print();
	else
		cout << "NULL";

}

void JoinNode::ExecutePostOrder()
{
	if (this->left)
		this->left->ExecutePostOrder();
	if (this->right)
		this->right->ExecutePostOrder();
	this->ExecuteNode();
}

void JoinNode::ExecuteNode()
{
	Join *join = new Join(); 
	join->Use_n_Pages(USE_PAGES);
	if (cnf != NULL && literal != NULL)
	{
		join->Run(*(OperatorNode::Pipes[InPipe]), *(OperatorNode::Pipes[rightInPipe]), 
				*(OperatorNode::Pipes[OutPipe]), *cnf, *literal,numAttsLeft,numAttsRight);
	}
	else
		cout << "\ncheck parameters!\n";
}


void GroupByNode::PrintNode()
{
	if (this->left != NULL)
		this->left->PrintNode();

	cout << "\n Group-by ";
	cout << "\nInput pipe ID: " << InPipe;
	cout << "\nOutput pipe ID: " << OutPipe;
	cout << "\nFunction: ";
	if (func)
		func->Print();
	else
		cout << "NULL\n";
	cout << "\nOrderMaker:\n";
	if (order)
		order->Print();
	else
		cout << "NULL\n";



	if (this->right != NULL)
		this->right->PrintNode();
}


void GroupByNode::ExecutePostOrder()
{
	if (this->left)
		this->left->ExecutePostOrder();
	if (this->right)
		this->right->ExecutePostOrder();
	this->ExecuteNode();
}

void GroupByNode::ExecuteNode()
{

	GroupBy* group = new GroupBy(); 
	group->Use_n_Pages(USE_PAGES);
	if (func != NULL && order!= NULL)
	{
		cout << "Group By about to run: Input: " << InPipe << " Output: " << OutPipe << "\n";
		group->Run(*(OperatorNode::Pipes[InPipe]), *(OperatorNode::Pipes[OutPipe]), *order, *func);
		cout << "Group by started\n";
		int s;
		//group->WaitUntilDone();
		cout << "Finished waiting\n";

		Record rec;
		Attribute DA = {"double", Double};
		Schema sum_sch ("sumsch", 1, &DA);
		while (OperatorNode::Pipes[OutPipe]->Remove (&rec)) 
		{
			rec.Print(&sum_sch);
			//rec.Project (numKeep,numAttsKeep,totAtts);
			//rec.Print(tmpSchema);
		}

	}
	else
		cout << "\n check parameters!\n";
}


void SumNode::PrintNode()
{
	if (this->left != NULL)
		this->left->PrintNode();

	cout << "\n Sum ";
	cout << "\nInput pipe ID: " << InPipe;
	cout << "\nOutput pipe ID: " << OutPipe;
	cout << "\nfunction ";
	func->Print();


	if (this->right != NULL)
		this->right->PrintNode();
}

void SumNode::ExecutePostOrder()
{
	if (this->left)
		this->left->ExecutePostOrder();
	if (this->right)
		this->right->ExecutePostOrder();
	this->ExecuteNode();
}

void SumNode::ExecuteNode()
{


	Sum sum;
	sum.Use_n_Pages(USE_PAGES);
	if (func != NULL)
	{
		sum.Run(*(OperatorNode::Pipes[InPipe]), *(OperatorNode::Pipes[OutPipe]), *func);

		if (print)
		{

			if (func->returnsInt == 1)
			{
				Record rec;
				Attribute IA = {"integer", Int};
				Schema sum_sch ("sum_sch", 1, &IA);
				sum.WaitUntilDone();
				while (OperatorNode::Pipes[OutPipe]->Remove (&rec))
				{
					rec.Print (&sum_sch);
				}
			}
			else // Sum output is double, so make schema with one double column
			{
				Record rec;
				Attribute DA = {"double", Double};
				Schema sum_sch ("sum_sch", 1, &DA);
				sum.WaitUntilDone();
				while (OperatorNode::Pipes[OutPipe]->Remove (&rec))
				{
					rec.Print (&sum_sch);
				}
			}
		}
	}
	else
		cout << "\ncheck parameters!\n";
}

void DuplicateNode::PrintNode()
{
	if (this->left != NULL)
		this->left->PrintNode();

	if (this->right != NULL)
		this->right->PrintNode();

	cout << "\n Duplicate Removal ";
	cout << "\nInput pipe ID: " << InPipe;
	cout << "\nOutput pipe ID: " << OutPipe;
}

void DuplicateNode::ExecutePostOrder()
{
	if (this->left)
		this->left->ExecutePostOrder();
	if (this->right)
		this->right->ExecutePostOrder();
	this->ExecuteNode();
}

void DuplicateNode::ExecuteNode()
{
	DuplicateRemoval duplicate;
	duplicate.Use_n_Pages(USE_PAGES);
	if (sch != NULL)
	{
		duplicate.Run(*(OperatorNode::Pipes[InPipe]), *(OperatorNode::Pipes[OutPipe]), *sch);
		if (print== 1)
		{
			Record rec;
			int count = 0;
			while (OperatorNode::Pipes[OutPipe]->Remove(&rec))
			{
				rec.Print(sch);
				count++;
			}
			cout << endl << count << " records removed from pipe " << OutPipe << endl;
		}
	} 
}



void WriteOutNode::PrintNode()
{
	if (this->left != NULL)
		this->left->PrintNode();

	if (this->right != NULL)
		this->right->PrintNode();

	cout << "\n WriteOut ";
	cout << "\nInput pipe ID: " << InPipe;
	cout << "\nOutput file: " << OutFileName;
}

void WriteOutNode::ExecutePostOrder()
{
	if (this->left)
		this->left->ExecutePostOrder();
	if (this->right)
		this->right->ExecutePostOrder();
	this->ExecuteNode();
}

void WriteOutNode::ExecuteNode()
{


	WriteOut write;
	if (sch != NULL && !OutFileName.empty())
	{
		int count = 0;
		FILE * myFile = fopen((char*)OutFileName.c_str(), "w");
		write.Run(*(OperatorNode::Pipes[InPipe]), myFile, *sch );
		write.WaitUntilDone();
		fclose(myFile);


	}

}





